/**
 * SSE (Server-Sent Events) service for AI content generation streaming.
 * Fallback option when WebSocket is not available.
 */

import { message } from 'antd';

export interface SSEConfig {
  url: string;
  reconnectInterval?: number;
  maxReconnectAttempts?: number;
}

export interface SSEMessage {
  event?: string;
  data: any;
  id?: string;
}

export class SSEService {
  private eventSource: EventSource | null = null;
  private config: Required<SSEConfig>;
  private reconnectAttempts = 0;
  private reconnectTimer: NodeJS.Timeout | null = null;
  private messageHandlers: Map<string, Function[]> = new Map();
  private isIntentionallyClosed = false;
  private url: string;

  constructor(config: SSEConfig) {
    this.config = {
      url: config.url,
      reconnectInterval: config.reconnectInterval || 3000,
      maxReconnectAttempts: config.maxReconnectAttempts || 5,
    };
    this.url = config.url;
  }

  /**
   * Connect to SSE endpoint.
   */
  connect(): Promise<void> {
    return new Promise((resolve, reject) => {
      try {
        this.isIntentionallyClosed = false;
        
        // Add authentication token if available
        const token = localStorage.getItem('access_token');
        const urlWithAuth = token 
          ? `${this.url}${this.url.includes('?') ? '&' : '?'}token=${encodeURIComponent(token)}`
          : this.url;

        this.eventSource = new EventSource(urlWithAuth);

        this.eventSource.onopen = () => {
          console.log('SSE connected to:', this.url);
          this.reconnectAttempts = 0;
          this.emit('connected', null);
          resolve();
        };

        this.eventSource.onerror = (error) => {
          console.error('SSE error:', error);
          this.emit('error', error);
          
          // EventSource will automatically reconnect, but we handle it manually
          this.eventSource?.close();
          
          if (!this.isIntentionallyClosed) {
            this.attemptReconnect();
          }
          
          // Only reject on initial connection
          if (this.reconnectAttempts === 0) {
            reject(error);
          }
        };

        // Handle default message event
        this.eventSource.onmessage = (event) => {
          this.handleMessage({
            data: this.parseData(event.data),
            id: event.lastEventId,
          });
        };

        // Register custom event listeners
        this.setupEventListeners();

      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * Disconnect from SSE.
   */
  disconnect(): void {
    this.isIntentionallyClosed = true;
    
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    
    if (this.eventSource) {
      this.eventSource.close();
      this.eventSource = null;
    }

    this.emit('disconnected', null);
  }

  /**
   * Register event handler.
   */
  on(event: string, handler: Function): void {
    if (!this.messageHandlers.has(event)) {
      this.messageHandlers.set(event, []);
    }
    this.messageHandlers.get(event)?.push(handler);

    // If EventSource exists, add listener for custom events
    if (this.eventSource && event !== 'message' && event !== 'connected' && event !== 'disconnected' && event !== 'error') {
      this.eventSource.addEventListener(event, (e: any) => {
        this.handleMessage({
          event,
          data: this.parseData(e.data),
          id: e.lastEventId,
        });
      });
    }
  }

  /**
   * Remove event handler.
   */
  off(event: string, handler?: Function): void {
    if (!handler) {
      this.messageHandlers.delete(event);
    } else {
      const handlers = this.messageHandlers.get(event);
      if (handlers) {
        const index = handlers.indexOf(handler);
        if (index > -1) {
          handlers.splice(index, 1);
        }
      }
    }
  }

  /**
   * Emit event to handlers.
   */
  private emit(event: string, data: any): void {
    const handlers = this.messageHandlers.get(event);
    if (handlers) {
      handlers.forEach(handler => handler(data));
    }
  }

  /**
   * Parse SSE data.
   */
  private parseData(data: string): any {
    try {
      return JSON.parse(data);
    } catch {
      return data;
    }
  }

  /**
   * Handle SSE message.
   */
  private handleMessage(message: SSEMessage): void {
    // Emit generic message event
    this.emit('message', message);
    
    // Emit specific event if available
    if (message.event) {
      this.emit(message.event, message.data);
    }
  }

  /**
   * Setup custom event listeners.
   */
  private setupEventListeners(): void {
    if (!this.eventSource) return;

    // Common SSE events for generation
    const events = ['token', 'complete', 'error', 'start', 'cancelled', 'connection'];
    
    events.forEach(eventName => {
      this.eventSource!.addEventListener(eventName, (e: any) => {
        this.handleMessage({
          event: eventName,
          data: this.parseData(e.data),
          id: e.lastEventId,
        });
      });
    });
  }

  /**
   * Attempt to reconnect.
   */
  private attemptReconnect(): void {
    if (this.reconnectAttempts >= this.config.maxReconnectAttempts) {
      console.error('Max SSE reconnection attempts reached');
      message.error('无法连接到流式服务，请刷新页面重试');
      return;
    }

    this.reconnectAttempts++;
    
    console.log(`Attempting SSE reconnect (${this.reconnectAttempts}/${this.config.maxReconnectAttempts})...`);
    
    this.reconnectTimer = setTimeout(() => {
      this.connect().catch(error => {
        console.error('SSE reconnection failed:', error);
      });
    }, this.config.reconnectInterval);
  }

  /**
   * Check if connected.
   */
  isConnected(): boolean {
    return this.eventSource?.readyState === EventSource.OPEN;
  }

  /**
   * Get connection state.
   */
  getState(): number {
    return this.eventSource?.readyState ?? EventSource.CLOSED;
  }
}

/**
 * SSE service specifically for generation streaming.
 */
export class GenerationSSEService extends SSEService {
  private taskId: string;
  private isGenerating = false;
  private generationHandlers: {
    onToken?: (token: string) => void;
    onComplete?: (metadata: any) => void;
    onError?: (error: string) => void;
    onStart?: (metadata: any) => void;
  } = {};

  constructor(taskId: string, templateId: string, model: string = 'gpt-4') {
    const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8001';
    
    super({
      url: `${apiUrl}/streaming/sse/generation/${taskId}?template_id=${templateId}&model=${model}`,
      reconnectInterval: 3000,
      maxReconnectAttempts: 3,
    });

    this.taskId = taskId;
    this.setupGenerationHandlers();
  }

  /**
   * Start SSE streaming.
   */
  async start(): Promise<void> {
    await this.connect();
    this.isGenerating = true;
  }

  /**
   * Cancel generation (requires separate API call).
   */
  async cancelGeneration(): Promise<void> {
    if (this.isGenerating) {
      const apiUrl = import.meta.env.VITE_API_URL || 'http://localhost:8001';
      const token = localStorage.getItem('access_token');

      try {
        const response = await fetch(
          `${apiUrl}/streaming/cancel/${this.taskId}`,
          {
            method: 'POST',
            headers: {
              'Authorization': `Bearer ${token}`,
            },
          }
        );

        if (response.ok) {
          this.isGenerating = false;
          this.disconnect();
        }
      } catch (error) {
        console.error('Failed to cancel generation:', error);
      }
    }
  }

  /**
   * Set generation event handlers.
   */
  setGenerationHandlers(handlers: {
    onToken?: (token: string) => void;
    onComplete?: (metadata: any) => void;
    onError?: (error: string) => void;
    onStart?: (metadata: any) => void;
  }): void {
    this.generationHandlers = handlers;
  }

  /**
   * Setup generation-specific handlers.
   */
  private setupGenerationHandlers(): void {
    this.on('token', (data: any) => {
      if (data.content && this.generationHandlers.onToken) {
        this.generationHandlers.onToken(data.content);
      }
    });

    this.on('complete', (data: any) => {
      this.isGenerating = false;
      if (this.generationHandlers.onComplete) {
        this.generationHandlers.onComplete(data);
      }
    });

    this.on('error', (data: any) => {
      this.isGenerating = false;
      if (data.error && this.generationHandlers.onError) {
        this.generationHandlers.onError(data.error);
      }
    });

    this.on('start', (data: any) => {
      if (this.generationHandlers.onStart) {
        this.generationHandlers.onStart(data);
      }
    });

    this.on('cancelled', () => {
      this.isGenerating = false;
      if (this.generationHandlers.onComplete) {
        this.generationHandlers.onComplete({ cancelled: true });
      }
    });
  }

  /**
   * Check if currently generating.
   */
  isCurrentlyGenerating(): boolean {
    return this.isGenerating;
  }
}

/**
 * Factory function to create generation SSE service.
 */
export function createGenerationSSE(
  taskId: string,
  templateId: string,
  model?: string
): GenerationSSEService {
  return new GenerationSSEService(taskId, templateId, model);
}